package com.wy.base;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWizard;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wst.common.componentcore.ArtifactEdit;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;

import com.wy.util.PluginUtils;

/**
 * 通用新建文件向导执行类
 *
 * @auther 飞花梦影
 * @date 2021-07-17 00:06:49
 * @git {@link https://github.com/dreamFlyingFlower}
 */
public abstract class AbstractWizard extends Wizard implements INewWizard {

	private static final Logger logger = Logger.getLogger(AbstractWizard.class.getName());

	private AbstractWizardPage page;

	private ISelection selection;

	public String projectName = null;

	public String packageName = null;

	public String fileName = null;

	protected boolean normal;

	protected boolean maven;

	private String[] jerseyJars;

	private String downloadSite = "http://karthy.me/repository";

	private String jerseyClass = "com.sun.jersey.server.impl.container.servlet.ServletAdaptor";

	public AbstractWizard() {
		super();
		setNeedsProgressMonitor(true);
		loadProperties();
	}

	protected void loadProperties() {
		Properties props = new Properties();
		try (InputStream is = getClass().getResourceAsStream("/properties/props.properties");) {
			props.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// 获得当前选中项目
		ISelectionService selectionService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService();
		ISelection selection = selectionService.getSelection();

		IProject project = null;
		if (selection instanceof IStructuredSelection) {
			Object element = ((IStructuredSelection) selection).getFirstElement();
			if (element instanceof IResource) {
				project = ((IResource) element).getProject();
			} else if (element instanceof IJavaElement) {
				IJavaProject jProject = ((IJavaElement) element).getJavaProject();
				project = jProject.getProject();
				String dreamUri = project.getLocation() + File.separator + "src" + File.separator + "main"
						+ File.separator + "resources" + File.separator + "props.properties";
				// 读取用户配置文件,只能是dream.properties
				try (InputStream isDream = new FileInputStream(new File(dreamUri));) {
					if (Objects.nonNull(isDream)) {
						props.load(isDream);
					}
				} catch (IOException e) {
					logger.info("No props.properties file be found");
				}
			}
		}
		handlerProperties(props);
	}

	protected void handlerProperties(Properties props) {
		this.jerseyClass = props.getProperty("jersey.class", jerseyClass);
		this.downloadSite = (props.getProperty("download.site") + "jersey/");
		StringTokenizer st = new StringTokenizer(props.getProperty("jersey.jars"), ",");
		String[] temp = new String[st.countTokens()];
		for (int i = 0; st.hasMoreTokens(); i++) {
			temp[i] = st.nextToken();
		}
		this.jerseyJars = temp;
	}

	/**
	 * 该方法在点击finish的时候调用
	 */
	@Override
	public abstract boolean performFinish();

	/**
	 * 点击Finish调用该事件
	 * 
	 * @param templateUri
	 * @return 操作是否成功
	 */
	protected boolean performFinish(String templateUri) {
		if (Objects.isNull(templateUri) || templateUri.isEmpty()) {
			return false;
		}
		projectName = getPage().getProjectName();
		packageName = getPage().getPackageName();
		fileName = getPage().getClassName();
		IRunnableWithProgress op = new IRunnableWithProgress() {

			@Override
			public void run(IProgressMonitor monitor) throws InvocationTargetException {
				try {
					doFinish(projectName, packageName, fileName, monitor, templateUri);
				} catch (CoreException e) {
					throw new InvocationTargetException(e);
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					monitor.done();
				}
			}
		};
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), "Error", realException.getMessage());
			return false;
		}
		return true;
	}

	/**
	 * 找到容器,创建该文件或替代原文件
	 * 
	 * The worker method. It will find the container, create the file if missing or
	 * just replace its contents, and open the editor on the newly created file.
	 */
	protected void doFinish(String containerName, String packageName, String fileName, IProgressMonitor monitor,
			String templateUri) throws Exception {
		String content = loadTemplate(containerName, templateUri);
		PluginUtils.createFile(containerName, packageName, fileName, monitor, content);
		additionalFinish(containerName, packageName, fileName, monitor, templateUri);
		monitor.worked(1);
	}

	protected void additionalFinish(String containerName, String packageName, String fileName, IProgressMonitor monitor,
			String templateUri) {

	}

	protected void throwCoreException(String message) throws CoreException {
		IStatus status = new Status(IStatus.ERROR, "Dream Simple Class Plugin", IStatus.OK, message, null);
		throw new CoreException(status);
	}

	protected String loadTemplate(String projectName, String templateUri) throws Exception {
		addServlet(projectName);
		StringBuilder sb = new StringBuilder();
		try (InputStream input = this.getClass().getResourceAsStream(templateUri);
				BufferedReader reader = new BufferedReader(new InputStreamReader(input));) {
			String line = null;
			int row = 0;
			while ((line = reader.readLine()) != null) {
				if (row != 0) {
					sb.append("\n");
				}
				line = line.replaceAll("#projectname", projectName);
				line = line.replaceAll("#package", packageName);
				line = line.replaceAll("#classname", fileName);
				line = line.replaceAll("#datetime",
						LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
				sb.append(line);
				row++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}

	protected void addServlet(String containerName) throws Exception {

	}

	/**
	 * We will accept the selection in the workbench to see if we can initialize
	 * from it.
	 *
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	@Override
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.selection = selection;
	}

	public IFolder getWebInfLibDir(IProject pj) {
		IVirtualComponent vc = ComponentCore.createComponent(pj);
		IVirtualFolder vf = vc.getRootFolder().getFolder("WEB-INF/lib");
		return (IFolder) vf.getUnderlyingFolder();
	}

	public void saveEdit(ArtifactEdit edit) {
		edit.saveIfNecessary(null);
		edit.dispose();
	}

	public AbstractWizardPage getPage() {
		return page;
	}

	public void setPage(AbstractWizardPage page) {
		this.page = page;
	}

	public ISelection getSelection() {
		return selection;
	}

	public void setSelection(ISelection selection) {
		this.selection = selection;
	}

	public String getProjectName() {
		return projectName;
	}

	public void setProjectName(String projectName) {
		this.projectName = projectName;
	}

	public String getPackageName() {
		return packageName;
	}

	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public boolean isMaven() {
		return maven;
	}

	public void setMaven(boolean maven) {
		this.maven = maven;
	}

	public boolean isNormal() {
		return normal;
	}

	public void setNormal(boolean normal) {
		this.normal = normal;
	}

	public String[] getJerseyJars() {
		return jerseyJars;
	}

	public void setJerseyJars(String[] jerseyJars) {
		this.jerseyJars = jerseyJars;
	}

	public String getDownloadSite() {
		return downloadSite;
	}

	public void setDownloadSite(String downloadSite) {
		this.downloadSite = downloadSite;
	}

	public String getJerseyClass() {
		return jerseyClass;
	}

	public void setJerseyClass(String jerseyClass) {
		this.jerseyClass = jerseyClass;
	}
}